package utils;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

public class HttpUtils {
    private static volatile CloseableHttpClient httpClient;

    static {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        // Increase max total connection to 200
        cm.setMaxTotal(200);
        // Increase default max connection per route to 10
        cm.setDefaultMaxPerRoute(10);
        RequestConfig requestConfig = RequestConfig.custom()
                                                   .setConnectTimeout(3000) //指客户端和服务器建立连接的timeout
                                                   .setSocketTimeout(30000) //指客户端从服务器读取数据的timeou
                                                   .setConnectionRequestTimeout(30000) //指从连接池获取连接的timeout
                                                   .build();
        httpClient = HttpClients.custom()
                                .setConnectionManager(cm)
                                .setDefaultRequestConfig(requestConfig)
                                .setSSLSocketFactory(createSSLConnectionSocketFactory())
                                .build();
    }

    public static SSLConnectionSocketFactory createSSLConnectionSocketFactory() {
        try {
            //使用 loadTrustMaterial() 方法实现一个信任策略，信任所有证书
            // 信任所有
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true)
                                                           .build();
            //NoopHostnameVerifier类:  作为主机名验证工具，实质上关闭了主机名验证，它接受任何
            //有效的SSL会话并匹配到目标主机。
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            return new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String doPostJSON(String host, String path, String accessToken, Map<String, Object> paramsMap) {
        return doPostJSON(host, path, accessToken, JSON.toJSONString(paramsMap, SerializerFeature.DisableCircularReferenceDetect));
    }

    /**
     * Post JSON
     *
     * @param host
     * @param path
     * @param accessToken
     * @param body
     * @return
     * @throws Exception
     */
    public static String doPostJSON(String host, String path, String accessToken, String body) {
        HttpPost request = new HttpPost(String.format("%s%s?access_token=%s", host, path, accessToken));
        request.addHeader("Content-Type", "application/json");
        if (StringUtils.isNotBlank(body)) {
            System.out.println(body);
            request.setEntity(new StringEntity(body, "UTF-8"));
        }
        try {
            HttpResponse response = httpClient.execute(request);
            int statusCode = response.getStatusLine()
                                     .getStatusCode();
            if (statusCode != 200) {
                System.out.println("Http code: " + statusCode);
                System.out.println("http header error msg: " + response.getFirstHeader("X-Ca-Error-Message"));
                System.out.println("Http body error msg:" + EntityUtils.toString(response.getEntity()));
                return null;
            }
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String doPost(String host, String path, String queryString, String body) {
        HttpPost request = new HttpPost(String.format("%s%s?%s", host, path, queryString));
        request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "UTF-8"));
        }
        try {
            HttpResponse response = httpClient.execute(request);
            int statusCode = response.getStatusLine()
                                     .getStatusCode();
            if (statusCode != 200) {
                System.out.println("Http code: " + statusCode);
                System.out.println("http header error msg: " + response.getFirstHeader("X-Ca-Error-Message"));
                System.out.println("Http body error msg:" + EntityUtils.toString(response.getEntity()));
                return null;
            }
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}